{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/bitkira/Colab/blob/main/tutorial_notebooks_zh/first_agent.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "!pip install git+https://github.com/EvoAgentX/EvoAgentX.git"
      ],
      "metadata": {
        "id": "ZBtwrAuZo-C1"
      },
      "id": "ZBtwrAuZo-C1",
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "!pip install PyPDF2 selenium html2text fastmcp"
      ],
      "metadata": {
        "id": "wcErYy4VpBWd"
      },
      "id": "wcErYy4VpBWd",
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "id": "c908aaf8",
      "metadata": {
        "id": "c908aaf8"
      },
      "source": [
        "# 构建你的第一个代理\n",
        "\n",
        "在 EvoAgentX 中，代理是设计用来自主完成特定任务的智能组件。本教程将引导你了解在 EvoAgentX 中创建和使用代理的基本概念：\n",
        "\n",
        "1. **使用 CustomizeAgent 创建简单代理**：学习如何使用自定义提示创建基本代理\n",
        "2. **使用多个动作**：创建可以执行多个任务的更复杂的代理\n",
        "3. **保存和加载代理**：学习如何保存和加载你的代理\n",
        "\n",
        "通过本教程，你将能够创建简单和复杂的代理，了解它们如何处理输入和输出，以及如何在项目中保存和重用它们。\n",
        "\n",
        "## 1. 使用 CustomizeAgent 创建简单代理\n",
        "\n",
        "创建代理最简单的方法是使用 `CustomizeAgent`，它允许你快速定义一个具有特定提示的代理。\n",
        "\n",
        "首先，让我们导入必要的组件并设置 LLM：\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "4124d1f4",
      "metadata": {
        "id": "4124d1f4"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "from dotenv import load_dotenv\n",
        "from evoagentx.models import OpenAILLMConfig, BaseLLM\n",
        "from evoagentx.agents import CustomizeAgent\n",
        "\n",
        "try:\n",
        "    from google.colab import userdata\n",
        "    OPENAI_API_KEY = userdata.get(\"OPENAI_API_KEY\")\n",
        "except ImportError:\n",
        "    OPENAI_API_KEY = None\n",
        "\n",
        "if not OPENAI_API_KEY:\n",
        "    load_dotenv()\n",
        "    OPENAI_API_KEY = os.getenv(\"OPENAI_API_KEY\")\n",
        "\n",
        "# Configure LLM\n",
        "openai_config = OpenAILLMConfig(\n",
        "    model=\"gpt-4o-mini\",\n",
        "    openai_key=OPENAI_API_KEY,\n",
        "    stream=True\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b3c0cf62",
      "metadata": {
        "id": "b3c0cf62"
      },
      "source": [
        "\n",
        "现在，让我们创建一个打印 hello world 的简单代理。有两种方法可以创建 CustomizeAgent：\n",
        "\n",
        "### 方法 1：直接初始化\n",
        "你可以直接使用 `CustomizeAgent` 类初始化代理："
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "426765b2",
      "metadata": {
        "id": "426765b2"
      },
      "outputs": [],
      "source": [
        "first_agent = CustomizeAgent(\n",
        "    name=\"FirstAgent\",\n",
        "    description=\"A simple agent that prints hello world\",\n",
        "    prompt=\"Print 'hello world'\",\n",
        "    llm_config=openai_config # specify the LLM configuration\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "18882838",
      "metadata": {
        "id": "18882838"
      },
      "source": [
        "\n",
        "### 方法 2：从字典创建\n",
        "\n",
        "你也可以通过定义字典中的配置来创建代理：\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "27160b73",
      "metadata": {
        "id": "27160b73"
      },
      "outputs": [],
      "source": [
        "agent_data = {\n",
        "    \"name\": \"FirstAgent\",\n",
        "    \"description\": \"A simple agent that prints hello world\",\n",
        "    \"prompt\": \"Print 'hello world'\",\n",
        "    \"llm_config\": openai_config\n",
        "}\n",
        "first_agent = CustomizeAgent.from_dict(agent_data) # use .from_dict() to create an agent."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8ae65acc",
      "metadata": {
        "id": "8ae65acc"
      },
      "source": [
        "\n",
        "### 使用代理\n",
        "\n",
        "创建完成后，你可以使用代理来打印 hello world。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "0199119f",
      "metadata": {
        "id": "0199119f"
      },
      "outputs": [],
      "source": [
        "# Execute the agent without input. The agent will return a Message object containing the results.\n",
        "message = await first_agent()\n",
        "\n",
        "print(f\"Response from {first_agent.name}:\")\n",
        "print(message.content.content) # the content of a Message object is a LLMOutputParser object, where the `content` attribute is the raw LLM output."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4bb01130",
      "metadata": {
        "id": "4bb01130"
      },
      "source": [
        "\n",
        "有关完整示例，请参考 [CustomizeAgent 示例](https://github.com/EvoAgentX/EvoAgentX/blob/main/examples/customize_agent.py)。\n",
        "\n",
        "CustomizeAgent 还提供其他功能，包括结构化输入/输出和多种解析策略。有关详细信息，请参阅 [CustomizeAgent 文档](../modules/customize_agent.md)。\n",
        "\n",
        "## 2. 创建具有多个动作的代理\n",
        "\n",
        "在 EvoAgentX 中，你可以创建一个具有多个预定义动作的代理。这允许你构建可以执行多个任务的更复杂的代理。以下是一个示例，展示如何创建一个具有 `TestCodeGeneration` 和 `TestCodeReview` 动作的代理：\n",
        "\n",
        "### 定义动作\n",
        "首先，我们需要定义动作，它们是 `Action` 的子类："
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "cda4f11b",
      "metadata": {
        "id": "cda4f11b"
      },
      "outputs": [],
      "source": [
        "from evoagentx.agents import Agent\n",
        "from evoagentx.actions import Action, ActionInput, ActionOutput\n",
        "from pydantic import Field\n",
        "from typing import Optional\n",
        "\n",
        "# Define the CodeGeneration action inputs\n",
        "class TestCodeGenerationInput(ActionInput):\n",
        "    requirement: str = Field(description=\"The requirement for the code generation\")\n",
        "\n",
        "# Define the CodeGeneration action outputs\n",
        "class TestCodeGenerationOutput(ActionOutput):\n",
        "    code: str = Field(description=\"The generated code\")\n",
        "\n",
        "# Define the CodeGeneration action\n",
        "class TestCodeGeneration(Action):\n",
        "\n",
        "    def __init__(\n",
        "        self,\n",
        "        name: str=\"TestCodeGeneration\",\n",
        "        description: str=\"Generate code based on requirements\",\n",
        "        prompt: str=\"Generate code based on requirements: {requirement}\",\n",
        "        inputs_format: ActionInput=None,\n",
        "        outputs_format: ActionOutput=None,\n",
        "        **kwargs\n",
        "    ):\n",
        "        inputs_format = inputs_format or TestCodeGenerationInput\n",
        "        outputs_format = outputs_format or TestCodeGenerationOutput\n",
        "        super().__init__(\n",
        "            name=name,\n",
        "            description=description,\n",
        "            prompt=prompt,\n",
        "            inputs_format=inputs_format,\n",
        "            outputs_format=outputs_format,\n",
        "            **kwargs\n",
        "        )\n",
        "\n",
        "    def execute(self, llm: Optional[BaseLLM] = None, inputs: Optional[dict] = None, sys_msg: Optional[str]=None, return_prompt: bool = False, **kwargs) -> TestCodeGenerationOutput:\n",
        "        action_input_attrs = self.inputs_format.get_attrs() # obtain the attributes of the action input\n",
        "        action_input_data = {attr: inputs.get(attr, \"undefined\") for attr in action_input_attrs}\n",
        "        prompt = self.prompt.format(**action_input_data) # format the prompt with the action input data\n",
        "        output = llm.generate(\n",
        "            prompt=prompt,\n",
        "            system_message=sys_msg,\n",
        "            parser=self.outputs_format,\n",
        "            parse_mode=\"str\" # specify how to parse the output\n",
        "        )\n",
        "        if return_prompt:\n",
        "            return output, prompt\n",
        "        return output\n",
        "\n",
        "\n",
        "# Define the CodeReview action inputs\n",
        "class TestCodeReviewInput(ActionInput):\n",
        "    code: str = Field(description=\"The code to be reviewed\")\n",
        "    requirements: str = Field(description=\"The requirements for the code review\")\n",
        "\n",
        "# Define the CodeReview action outputs\n",
        "class TestCodeReviewOutput(ActionOutput):\n",
        "    review: str = Field(description=\"The review of the code\")\n",
        "\n",
        "# Define the CodeReview action\n",
        "class TestCodeReview(Action):\n",
        "    def __init__(\n",
        "        self,\n",
        "        name: str=\"TestCodeReview\",\n",
        "        description: str=\"Review the code based on requirements\",\n",
        "        prompt: str=\"Review the following code based on the requirements:\\n\\nRequirements: {requirements}\\n\\nCode:\\n{code}.\\n\\nYou should output a JSON object with the following format:\\n```json\\n{{\\n'review': '...'\\n}}\\n```\",\n",
        "        inputs_format: ActionInput=None,\n",
        "        outputs_format: ActionOutput=None,\n",
        "        **kwargs\n",
        "    ):\n",
        "        inputs_format = inputs_format or TestCodeReviewInput\n",
        "        outputs_format = outputs_format or TestCodeReviewOutput\n",
        "        super().__init__(\n",
        "            name=name,\n",
        "            description=description,\n",
        "            prompt=prompt,\n",
        "            inputs_format=inputs_format,\n",
        "            outputs_format=outputs_format,\n",
        "            **kwargs\n",
        "        )\n",
        "\n",
        "    def execute(self, llm: Optional[BaseLLM] = None, inputs: Optional[dict] = None, sys_msg: Optional[str]=None, return_prompt: bool = False, **kwargs) -> TestCodeReviewOutput:\n",
        "        action_input_attrs = self.inputs_format.get_attrs()\n",
        "        action_input_data = {attr: inputs.get(attr, \"undefined\") for attr in action_input_attrs}\n",
        "        prompt = self.prompt.format(**action_input_data)\n",
        "        output = llm.generate(\n",
        "            prompt=prompt,\n",
        "            system_message=sys_msg,\n",
        "            parser=self.outputs_format,\n",
        "            parse_mode=\"json\" # specify how to parse the output\n",
        "        )\n",
        "        if return_prompt:\n",
        "            return output, prompt\n",
        "        return output"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "109b25b6",
      "metadata": {
        "id": "109b25b6"
      },
      "source": [
        "\n",
        "从上面的示例中，我们可以看到，为了定义一个动作，我们需要：\n",
        "\n",
        "1. 使用 `ActionInput` 和 `ActionOutput` 类定义动作的输入和输出\n",
        "2. 创建一个继承自 `Action` 的动作类\n",
        "3. 实现 `execute` 方法，该方法使用动作输入数据格式化提示，并使用 LLM 生成输出，并通过 `parse_mode` 指定如何解析输出。\n",
        "\n",
        "### 定义代理\n",
        "\n",
        "一旦我们定义了动作，我们就可以通过将动作添加到代理中来创建代理：\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "ada2d075",
      "metadata": {
        "id": "ada2d075"
      },
      "outputs": [],
      "source": [
        "# Initialize the LLM\n",
        "openai_config = OpenAILLMConfig(model=\"gpt-4o-mini\", openai_key=OPENAI_API_KEY)\n",
        "\n",
        "# Define the agent\n",
        "developer = Agent(\n",
        "    name=\"Developer\",\n",
        "    description=\"A developer who can write code and review code\",\n",
        "    actions=[TestCodeGeneration(), TestCodeReview()],\n",
        "    llm_config=openai_config\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "11ffb09e",
      "metadata": {
        "id": "11ffb09e"
      },
      "source": [
        "\n",
        "### 执行不同的动作\n",
        "\n",
        "一旦你创建了一个具有多个动作的代理，你可以执行特定的动作：\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "290fcb1d",
      "metadata": {
        "id": "290fcb1d"
      },
      "outputs": [],
      "source": [
        "# List all available actions on the agent\n",
        "actions = developer.get_all_actions()\n",
        "print(f\"Available actions of agent {developer.name}:\")\n",
        "for action in actions:\n",
        "    print(f\"- {action.name}: {action.description}\")\n",
        "\n",
        "# Generate some code using the CodeGeneration action\n",
        "generation_result = developer.execute(\n",
        "    action_name=\"TestCodeGeneration\", # specify the action name\n",
        "    action_input_data={\n",
        "        \"requirement\": \"Write a function that returns the sum of two numbers\"\n",
        "    }\n",
        ")\n",
        "\n",
        "# Access the generated code\n",
        "generated_code = generation_result.content.code\n",
        "print(\"Generated code:\")\n",
        "print(generated_code)\n",
        "\n",
        "# Review the generated code using the CodeReview action\n",
        "review_result = developer.execute(\n",
        "    action_name=\"TestCodeReview\",\n",
        "    action_input_data={\n",
        "        \"requirements\": \"Write a function that returns the sum of two numbers\",\n",
        "        \"code\": generated_code\n",
        "    }\n",
        ")\n",
        "\n",
        "# Access the review results\n",
        "review = review_result.content.review\n",
        "print(\"\\nReview:\")\n",
        "print(review)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5b32ceda",
      "metadata": {
        "id": "5b32ceda"
      },
      "source": [
        "\n",
        "这个示例演示了如何：\n",
        "1. 列出代理上可用的所有动作\n",
        "2. 使用 TestCodeGeneration 动作生成代码\n",
        "3. 使用 TestCodeReview 动作审查生成的代码\n",
        "4. 访问每个动作执行的结果\n",
        "\n",
        "有关完整的工作示例，请参考 [Agent 示例](https://github.com/EvoAgentX/EvoAgentX/blob/main/examples/agent_with_multiple_actions.py)。\n",
        "\n",
        "\n",
        "## 3. 保存和加载代理\n",
        "\n",
        "你可以将代理保存到文件并在稍后加载它：\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "66a5a677",
      "metadata": {
        "id": "66a5a677"
      },
      "outputs": [],
      "source": [
        "# 保存代理\n",
        "developer.save_module(\"examples/output/developer.json\")\n",
        "\n",
        "# 加载代理\n",
        "loaded_developer = Agent.load_module(\"examples/output/developer.json\", llm_config=openai_config)"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "new",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "name": "python",
      "version": "3.13.5"
    },
    "colab": {
      "provenance": [],
      "include_colab_link": true
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}